package chat

import (
	"log"
	"net"
	"runtime"
	"time"

	netpack "im/im_server/proto"
	"im/im_server/tcp_server"

	"github.com/go-redis/redis/v9"
	"google.golang.org/protobuf/proto"
)

type ChatServer struct {
	listener       net.Listener
	conns          map[*Connection]bool
	broadcast      chan []byte
	register       chan *Connection
	unregister     chan *Connection
	msgCallback    chan func() // 实现跨线程调用
	redisCmd       *RedisCmd
	registerPlayer chan *Connection      // 检查登陆注册玩家信息
	playerConns    map[int64]*Connection // 维护所有玩家id映射
}

func NewChatServer(addr string) *ChatServer {
	redisCmd := &RedisCmd{}
	redisCmd.redisClient = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // no password set
		DB:       0,  // use default DB
	})

	return &ChatServer{
		listener:       tcp_server.ListenTcpOrDie(addr),
		conns:          make(map[*Connection]bool),
		broadcast:      make(chan []byte, 1024),
		register:       make(chan *Connection),
		unregister:     make(chan *Connection),
		msgCallback:    make(chan func(), 1024),
		redisCmd:       redisCmd,
		registerPlayer: make(chan *Connection),
		playerConns:    make(map[int64]*Connection),
	}
}

func (s *ChatServer) ServerConn(conn net.Conn) {
	c := &Connection{
		conn:   conn,
		send:   make(chan []byte, 1024),
		player: NewPlayer(),
	}

	c.player.registerMessage(s)

	s.register <- c
	defer func() { s.unregister <- c }()
	go c.output()
	c.input()
}

func (s *ChatServer) BroadcastChat(id netpack.MessageID, m proto.Message) error {
	msg, err := proto.Marshal(m)
	if err != nil {
		return err
	}

	protocol := &netpack.Protocol{}
	protocol.Id = id
	protocol.Msg = msg

	replyData, err := proto.Marshal(protocol)
	if err != nil {
		return err
	}

	s.broadcast <- replyData
	return nil
}

func (s *ChatServer) delete(c *Connection) {
	delete(s.conns, c)
	if c.player.isLogin() {
		delete(s.playerConns, c.player.PlayerId)
	}
	close(c.send)
}

func (s *ChatServer) Run() {
	ticks := time.Tick(time.Second * 10)
	go tcp_server.ServerTcp(s.listener, s, "chat")
	for {
		select {
		case c, ok := <-s.register:
			if ok {
				s.conns[c] = true
			}
		case c, ok := <-s.registerPlayer:
			if ok {
				conn, ok := s.playerConns[c.player.PlayerId]
				if ok {
					// 顶号，踢掉查询到的玩家
					conn.kick()
				}
				s.playerConns[c.player.PlayerId] = c
			}
		case call := <-s.msgCallback:
			call()
		case c := <-s.unregister:
			s.delete(c)
		case m := <-s.broadcast:
			for c := range s.conns {
				select {
				// if cap(c.send) > 1024 {
				//	continue
				// }
				case c.send <- m:
				default:
					// 1.m空， 2.c.send 被关闭
					s.delete(c)
					log.Println("Kick slow connection")
				}
			}
		case _ = <-ticks:
			log.Println(len(s.conns), runtime.NumGoroutine())
		}
	}
}
